package com.xiaoma.verbal.service;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import org.springframework.beans.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import com.xiaoma.tpo.dao.ClsClassDao;
import com.xiaoma.tpo.domain.ClsClass;
import com.xiaoma.tpo.utils.Pager;
import com.xiaoma.tpo.utils.UploadImgUtil;
import com.xiaoma.verbal.dao.FctForecastDao;
import com.xiaoma.verbal.dao.FctQuestionDao;
import com.xiaoma.verbal.dao.PrctPracticeAudioDao;
import com.xiaoma.verbal.dao.QuQuestionDao;
import com.xiaoma.verbal.dao.QuTagDao;
import com.xiaoma.verbal.domain.FctForecast;
import com.xiaoma.verbal.domain.FctQuestion;
import com.xiaoma.verbal.domain.QuClassic;
import com.xiaoma.verbal.domain.QuQuestion;
import com.xiaoma.verbal.dto.ForecastVo;
import com.xiaoma.verbal.dto.QuestionVo;
import com.xiaoma.verbal.dto.QuestionVo;
import com.xiaoma.verbal.dto.Top3ForecastVo;
import com.xiaoma.verbal.utils.Constants;
import com.xiaoma.verbal.utils.DateUtil;
import com.xiaoma.verbal.utils.ExcelUtil;
import com.xiaoma.verbal.utils.MemoryDB;
import com.xiaoma.verbal.utils.UUIDGenerator;

@Service
@Transactional
public class ForecastService extends BaseQuestionService {
	@Autowired
	private FctForecastDao fctForecastDao;

	@Autowired
	private FctQuestionDao fctQuestionDao;

	@Autowired
	private QuTagDao quTagDao;

	@Autowired
	private QuQuestionDao quQuestionDao;
	@Autowired
	private ClsClassDao clsClassDao;
	@Autowired
	private PrctPracticeAudioDao prctPracticeAudioDao;

	@SuppressWarnings("unchecked")
	public List<FctForecast> findTop3() {
		return fctForecastDao.findTop3();
	}

	@SuppressWarnings("unchecked")
	public List<QuestionVo> findFQubyId(Integer fctId) {
		return fctQuestionDao.findFQubyId(fctId);
	}

	@SuppressWarnings("unchecked")
	@Transactional(readOnly = true)
	public Top3ForecastVo findTop3Forecast() throws IllegalAccessException, InvocationTargetException {

		List<FctForecast> list = fctForecastDao.findTop3();
		List<ForecastVo> newList = new ArrayList<ForecastVo>();

		Long time = 0L;
		Integer[] forecateIds = new Integer[list.size()];
		for (int i = 0; i < list.size(); i++) {
			FctForecast fct = list.get(i);
			forecateIds[i] = fct.getId();
			ForecastVo forecast = new ForecastVo();
			BeanUtils.copyProperties(fct,forecast);
			newList.add(forecast);
			forecast.setTitle(this.dealTitle(fct.getTimeRange1(), fct.getTimeRange2()));
			List<QuestionVo> questions = fctQuestionDao.findFQubyId(forecast.getId());
			for (QuestionVo vo : questions) {
				vo.setTags(this.quTagDao.findTagByQuestionId(vo.getId()));
			}
			forecast.setQuestions(questions);
			time = time + forecast.getUpdateTime().getTime();
		}
		Long timeCoordinate = this.dealUpdateTime(time, forecateIds);
		Top3ForecastVo top3 = new Top3ForecastVo();
		top3.setForecasts(newList);
		top3.setHasUpdate(true);
		top3.setUpdateTime(timeCoordinate);
		return top3;
	}

	@SuppressWarnings("unchecked")
	@Transactional(readOnly = true)
	public Top3ForecastVo findTop3ForecastByCheckUpdate(Boolean checkUpdate, Long lastUpdateTime) throws IllegalAccessException, InvocationTargetException {
		Top3ForecastVo top3 = new Top3ForecastVo();
		if (checkUpdate != null && checkUpdate) {
			if (this.hasNewTop3(lastUpdateTime, true)) {
				return top3 = this.findTop3Forecast();
			}
		}
		top3.setForecasts(new ArrayList<ForecastVo>());
		top3.setHasUpdate(false);
		top3.setUpdateTime(lastUpdateTime);
		return top3;

	}

	private String dealTitle(Date timeRange1, Date timeRange2) {
		SimpleDateFormat df = new SimpleDateFormat("M月dd日");
		String title = "";
		String start = null;
		String end = null;
		if (timeRange1 != null) {
			start = df.format(timeRange1);
		}

		// if (timeRange2 != null) {
		// end = df.format(timeRange2);
		// }
		// title = (start != null ? start : "") + (end != null ? "-" + end :
		// "");
		title = start;
		return title;
	}

	private Long dealUpdateTime(Long updateTime, Integer[] forecateIds) {
		Map<String, Object> coordinate = fctQuestionDao.getTop3Coordinate(forecateIds);
		Integer total = Integer.valueOf(coordinate.get("total").toString());
		Long sumTime = Long.valueOf(coordinate.get("sumTime").toString());
		return updateTime + total + sumTime;
	}

	public Boolean hasNewTop3(Long lastUpdateTime, Boolean cacheAble) {
		if (lastUpdateTime == null)
			return true;
		Long timeCoordinate = 0L;
		if (cacheAble) {
			timeCoordinate = (Long) MemoryDB.get(Constants.FTC);
		} else {
			timeCoordinate = this.getTimeCoordinate();
		}

		if (timeCoordinate.longValue() == lastUpdateTime.longValue()) {
			return false;
		}
		return true;
	}

	@Transactional(readOnly = true)
	public Long getTimeCoordinate() {
		List<FctForecast> list = fctForecastDao.findTop3();

		Long time = 0L;
		Integer[] forecateIds = new Integer[list.size()];
		for (int i = 0; i < list.size(); i++) {
			FctForecast fct = list.get(i);
			forecateIds[i] = fct.getId();
			time = time + fct.getUpdateTime().getTime();
		}
		Long timeCoordinate = this.dealUpdateTime(time, forecateIds);
		return timeCoordinate;
	}
	@Transactional(rollbackFor = Exception.class)
	public Integer[] importData(int version, InputStream in) {

		Integer[] result = new Integer[2];
		result[0] = 1;
		List<Map<String, Object>> list = null;
		try {
			// excel数据
			if (version == 2003) {
				list = ExcelUtil.parseExcel_2003(in);
			} else {
				list = ExcelUtil.parseExcel_2007(in);
			}

		} catch (Exception e) {
			e.printStackTrace();
			result[0] = 2;
			return result;
		}
		try {
			// 保存数据
			// 预测基本信息
			FctForecast f = mapToForecast(list.get(0));
			if (f.getId() != null) {
				fctQuestionDao.deleteByForecastId(f.getId());
			} else {
				f.setId(fctForecastDao.insert(f));
			}
			// 选题信息
			List<Map<String, Object>> qsinfo = new ArrayList<Map<String, Object>>();
			for (int i = 1; i < list.size(); i++) {
				qsinfo.add(list.get(i));
			}
			int errdatacount = SelQuestion(f, qsinfo);
			result[1] = errdatacount;
			// 刷新缓存
			this.afterChanger();
		} catch (Exception e) {
			e.printStackTrace();
			result[0] = 3;
			return result;
		}
		return result;
	}

	/**
	 * map to forecast
	 * 
	 * @param m
	 * @return
	 */
	private FctForecast mapToForecast(Map<String, Object> m) throws Exception {
		String forecast_num = (String) m.get("forecast_num");
		String forecast_date_1 = (String) m.get("forecast_date_1");
		String forecast_date_2 = (String) m.get("forecast_date_2");
		forecast_date_1 = DateUtil.dateStrFormat(forecast_date_1);
		forecast_date_2 = DateUtil.dateStrFormat(forecast_date_2);
		forecast_num = forecast_num.substring(forecast_num.lastIndexOf("_") + 1);
		int fnum = Integer.parseInt(forecast_num);
		FctForecast f = fctForecastDao.findForecastByfnum(fnum + "");
		if (f == null) {
			f = new FctForecast();
			f.setStatus(1);
		}
		f.setForecastNum(fnum);
		f.setTimeRange1(DateUtil.strToDate(forecast_date_1, "yyyy-MM-dd"));
		f.setTimeRange2(DateUtil.strToDate(forecast_date_2, "yyyy-MM-dd"));
		return f;
	}

	/**
	 * 选题
	 * 
	 * @param m
	 * @throws Exception
	 */
	private int SelQuestion(FctForecast f, List<Map<String, Object>> list) throws Exception {

		int errdatacount = 0;

		if (list != null && list.size() > 0) {
			for (Map<String, Object> m : list) {

				String question_num = (String) m.get("question_num");
				String import_num = (String) m.get("import_num");
				String qf_index = (String) m.get("qf_index");

				FctQuestion qf = new FctQuestion();
				QuQuestion qb = quQuestionDao.findByQnum(question_num);
				if (qb != null) {
					qf.setCreateTime(new Date());
					qf.setForecastId(f.getId());
					qf.setImportNum(((Double) Double.parseDouble(import_num)).intValue());
					qf.setIndex(((Double) Double.parseDouble(qf_index)).intValue());
					qf.setUuid(UUIDGenerator.getUUID());
					fctQuestionDao.insert(qf);
				} else {
					errdatacount++;
				}
			}
		}
		return errdatacount;
	}

	public Pager list(Integer fid, Integer forecastNum, String timeRange, Integer status, Integer top, Integer page, Integer pageSize) {
		// TODO Auto-generated method stub
		if (page == null || page==0) {
			page = 1;
			pageSize = 50;
		}
		return this.fctForecastDao.queryPageList(fid, forecastNum, timeRange, status, top, (page - 1) * pageSize, pageSize);
	}

	public FctForecast findById(Integer fid) {
		// TODO Auto-generated method stub
		return this.fctForecastDao.getById(fid);

	}

	@Transactional(rollbackFor = Exception.class)
	public void update(MultipartFile imgUrl,String name,String desc,String type,Integer seqNum,String recommended,String frequency,String[] qnums, Integer fid, Integer forecastNum, Integer status, String timeRange) throws ParseException {
		//通过机经ID获取课程ID
		FctForecast bean = this.fctForecastDao.getById(fid);
		//再通过cls_class_id 获取class
		String url = uploadImage(imgUrl);
		ClsClass clsClass = clsClassDao.getById(bean.getClsClassId());
		clsClass.setDesc(desc);
		clsClass.setImgUrl(url);
		clsClass.setName(name);
		clsClass.setType(type);
		clsClass.setSeqNum(seqNum);
		if("0".equals(recommended)){
			clsClass.setRecommended(false);
		}
		if("1".equals(recommended)){
			clsClass.setRecommended(true);
		}
		clsClass.setFrequency(Integer.parseInt(frequency));
		clsClassDao.update(clsClass);
		// TODO Auto-generated method stub
		if (bean != null) {
			if (forecastNum != null) {
				bean.setForecastNum(forecastNum);
			}
			if (timeRange != null) {
				bean.setTimeRange1(DateUtil.strToDate(timeRange, "yyyy-MM-dd"));

			}
			if (status != null) {
				bean.setStatus(status);

			} else {
				bean.setStatus(0);
			}
			bean.setUpdateTime(new Date());
			this.fctForecastDao.update(bean);
			// 重新关联问题
			this.dealQuestion(bean, qnums);
			// 刷新缓存
			this.afterChanger();
		}
	}
	@Transactional(rollbackFor = Exception.class)
	public void save(MultipartFile imgUrl,String name,String desc,String type,Integer seqNum,String recommended,String frequency,String[] qnums, Integer forecastNum, Integer status, String timeRange) throws ParseException {
		//在课程中只保存机经
		String url = uploadImage(imgUrl);
		ClsClass clsClass = new ClsClass();
		clsClass.setType(type);
		clsClass.setDesc(desc);
		clsClass.setName(name);
		clsClass.setImgUrl(url);
		clsClass.setSeqNum(seqNum);
		clsClass.setType(type);
		if("0".equals(recommended)){
			clsClass.setRecommended(false);
		}
		if("1".equals(recommended)){
			clsClass.setRecommended(true);
		}
		clsClass.setFrequency(Integer.parseInt(frequency));
		int clsClassId = clsClassDao.insert(clsClass);
		
		// TODO Auto-generated method stub
		FctForecast bean = new FctForecast();
		if (forecastNum != null) {
			bean.setForecastNum(forecastNum);
		}
		if (timeRange != null) {
			bean.setTimeRange1(DateUtil.strToDate(timeRange, "yyyy-MM-dd"));

		}
		if (status != null) {
			bean.setStatus(status);

		} else {
			bean.setStatus(0);
		}
		bean.setClsClassId(clsClassId);
		bean.setUpdateTime(new Date());
		bean.setCreateTime(bean.getUpdateTime());
		bean.setId(this.fctForecastDao.insert(bean));
		// 重新关联问题
		this.dealQuestion(bean, qnums);
		// 刷新缓存
		this.afterChanger();
	}
	//上传图片
   public String uploadImage(MultipartFile image){
		//将图片保存到右拍云
		String path = null;
		try {
			if(image != null && !image.isEmpty()){
				Integer lastIndex = image.getOriginalFilename().lastIndexOf(".");
				String postfix = image.getOriginalFilename().substring(lastIndex);
				String fileName = UUID.randomUUID().toString()+postfix;
				 path = UploadImgUtil.uploadImg(image.getBytes(), fileName);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return path;
	}
	/**
	 * 重新关联问题
	 * 
	 * @param bean
	 * @param qnums
	 */
	private void dealQuestion(FctForecast bean, String[] qnums) {
		this.fctQuestionDao.deleteByForecastId(bean.getId());
		if (qnums != null) {
			int i = 0;
			for (String qnum : qnums) {
				QuQuestion qst = this.quQuestionDao.findByQnum(qnum);
				if (qst != null) {
					FctQuestion fct = new FctQuestion();
					fct.setQuestionId(qst.getId());
					fct.setForecastId(bean.getId());
					fct.setClsClassId(bean.getClsClassId());
					String uuid=null;
					List<FctQuestion> list = this.fctQuestionDao.findByColumns(fct);
					if (!CollectionUtils.isEmpty(list)) {
						for (FctQuestion del : list) {
							uuid = del.getUuid();
							this.fctQuestionDao.destroy(del.getId());
						}
					}
					fct.setUuid(uuid!=null?uuid:UUIDGenerator.getUUID());
					fct.setCreateTime(new Date());
					fct.setForecastId(bean.getId());
					this.fctQuestionDao.insert(fct);
				}
			}
		}

	}

	public int hasForecastNum(Integer forecastNum) {
		// TODO Auto-generated method stub
		FctForecast bean = new FctForecast();
		bean.setForecastNum(forecastNum);
		if (!CollectionUtils.isEmpty(this.fctForecastDao.findByColumns(bean))) {
			return 1;
		}
		return 0;
	}
	/**
	 * 
	 *新的findTop3ForecastByCheckUpdate
	 * 
	 */
	//新的---findTop3ForecastByCheckUpdate
	@SuppressWarnings("unchecked")
	@Transactional(readOnly = true)
	public Top3ForecastVo findTop3ForecastByCheckUpdateNew(Boolean checkUpdate, Long lastUpdateTime,Integer clsClassId,Integer userId) throws IllegalAccessException, InvocationTargetException {
		Top3ForecastVo top3 = new Top3ForecastVo();
		if (checkUpdate != null && checkUpdate) {
			if (this.hasNewTop3(lastUpdateTime, true)) {
				return top3 = this.findTop3ForecastNew(clsClassId,userId);
			}
		}
		top3.setForecasts(new ArrayList<ForecastVo>());
		top3.setHasUpdate(false);
		top3.setUpdateTime(lastUpdateTime);
		return top3;

	}
	//新的---findTop3ForecastNew
	@SuppressWarnings("unchecked")
	@Transactional(readOnly = true)
	public Top3ForecastVo findTop3ForecastNew(Integer clsClassId,Integer userId) throws IllegalAccessException, InvocationTargetException {

		List<FctForecast> list = fctForecastDao.findTop3();
		List<ForecastVo> newList = new ArrayList<ForecastVo>();

		Long time = 0L;
		Integer[] forecateIds = new Integer[list.size()];
		for (int i = 0; i < list.size(); i++) {
			FctForecast fct = list.get(i);
			forecateIds[i] = fct.getId();
			ForecastVo forecast = new ForecastVo();
			BeanUtils.copyProperties(fct,forecast);
			newList.add(forecast);
			forecast.setTitle(this.dealTitle(fct.getTimeRange1(), fct.getTimeRange2()));
			List<QuestionVo> questions = fctQuestionDao.findFQubyId(forecast.getId());
			for (QuestionVo vo : questions) {
				vo.setTags(this.quTagDao.findTagByQuestionId(vo.getId()));
				boolean yonCommit = prctPracticeAudioDao.findbyClsIdAndQuestionNumAndUserId(clsClassId, vo.getQuestionNum(), userId);
				vo.setYonCommit(yonCommit);
			}
			forecast.setQuestions(questions);
			time = time + forecast.getUpdateTime().getTime();
		}
		Long timeCoordinate = this.dealUpdateTime(time, forecateIds);
		Top3ForecastVo top3 = new Top3ForecastVo();
		top3.setForecasts(newList);
		top3.setHasUpdate(true);
		top3.setUpdateTime(timeCoordinate);
		return top3;
	}
}
